package com.lifeverse.service;

import com.lifeverse.entity.AuditLog;
import com.lifeverse.entity.enums.AuditAction;
import com.lifeverse.entity.enums.AuditResult;
import com.lifeverse.repository.AuditLogRepository;
import com.lifeverse.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 审计日志服务
 * 提供审计日志的记录、查询、分析等功能
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class AuditLogService {
    
    private final AuditLogRepository auditLogRepository;
    
    /**
     * 异步记录审计日志
     */
    @Async
    public CompletableFuture<AuditLog> logAsync(AuditLog auditLog) {
        try {
            AuditLog savedLog = auditLogRepository.save(auditLog);
            log.debug("审计日志记录成功: {}", savedLog.getId());
            return CompletableFuture.completedFuture(savedLog);
        } catch (Exception e) {
            log.error("记录审计日志失败", e);
            return CompletableFuture.failedFuture(e);
        }
    }
    
    /**
     * 同步记录审计日志
     */
    public AuditLog log(AuditLog auditLog) {
        try {
            return auditLogRepository.save(auditLog);
        } catch (Exception e) {
            log.error("记录审计日志失败", e);
            throw new RuntimeException("记录审计日志失败", e);
        }
    }
    
    /**
     * 记录成功操作
     */
    public AuditLog logSuccess(String userId, String username, AuditAction action,
                              String resourceType, String resourceId, String description) {
        AuditLog auditLog = AuditLog.create(userId, username, action, resourceType, resourceId, description)
                .withRiskLevel(action.getRiskLevel());
        
        if (action.isSensitiveAction()) {
            auditLog.markAsSensitive();
        }
        
        return log(auditLog);
    }
    
    /**
     * 记录失败操作
     */
    public AuditLog logFailure(String userId, String username, AuditAction action,
                              String resourceType, String resourceId, String description,
                              String errorMessage) {
        AuditLog auditLog = AuditLog.createFailure(userId, username, action, resourceType, 
                                                  resourceId, description, errorMessage)
                .withRiskLevel(Math.max(action.getRiskLevel(), 3));
        
        if (action.isSensitiveAction()) {
            auditLog.markAsSensitive();
        }
        
        return log(auditLog);
    }
    
    /**
     * 记录HTTP请求的审计日志
     */
    public AuditLog logHttpRequest(HttpServletRequest request, String userId, String username,
                                  AuditAction action, String resourceType, String resourceId,
                                  String description, AuditResult result, String errorMessage,
                                  Long durationMs, Integer responseStatus) {
        
        AuditLog auditLog = AuditLog.builder()
                .userId(userId)
                .username(username)
                .action(action)
                .resourceType(resourceType)
                .resourceId(resourceId)
                .description(description)
                .result(result)
                .errorMessage(errorMessage)
                .timestamp(LocalDateTime.now())
                .riskLevel(action.getRiskLevel())
                .isSensitive(action.isSensitiveAction())
                .build();
        
        // 设置请求信息
        auditLog.withRequestInfo(
                getClientIpAddress(request),
                request.getHeader("User-Agent"),
                request.getSession(false) != null ? request.getSession().getId() : null,
                request.getRequestURI(),
                request.getMethod(),
                filterSensitiveParams(request.getParameterMap())
        );
        
        // 设置响应信息
        auditLog.withResponseInfo(responseStatus, durationMs);
        
        return log(auditLog);
    }
    
    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }
    
    /**
     * 过滤敏感参数
     */
    private String filterSensitiveParams(Map<String, String[]> parameterMap) {
        if (parameterMap == null || parameterMap.isEmpty()) {
            return null;
        }
        
        Map<String, String[]> filteredParams = parameterMap.entrySet().stream()
                .collect(java.util.stream.Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> {
                            String key = entry.getKey().toLowerCase();
                            if (key.contains("password") || key.contains("token") || 
                                key.contains("secret") || key.contains("key")) {
                                return new String[]{"[FILTERED]"};
                            }
                            return entry.getValue();
                        }
                ));
        
        try {
            return JsonUtils.toJson(filteredParams);
        } catch (Exception e) {
            log.warn("序列化请求参数失败", e);
            return "[SERIALIZATION_ERROR]";
        }
    }
    
    /**
     * 根据用户ID查询审计日志
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findByUserId(String userId, Pageable pageable) {
        return auditLogRepository.findByUserId(userId, pageable);
    }
    
    /**
     * 根据操作类型查询审计日志
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findByAction(AuditAction action, Pageable pageable) {
        return auditLogRepository.findByAction(action, pageable);
    }
    
    /**
     * 根据时间范围查询审计日志
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findByTimeRange(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
        return auditLogRepository.findByTimestampBetween(startTime, endTime, pageable);
    }
    
    /**
     * 查询失败的操作
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findFailedOperations(Pageable pageable) {
        return auditLogRepository.findFailedOperations(pageable);
    }
    
    /**
     * 查询敏感操作
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findSensitiveOperations(Pageable pageable) {
        return auditLogRepository.findByIsSensitiveTrue(pageable);
    }
    
    /**
     * 查询高风险操作
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findHighRiskOperations(Integer minRiskLevel, Pageable pageable) {
        return auditLogRepository.findByRiskLevelGreaterThanEqual(minRiskLevel, pageable);
    }
    
    /**
     * 多条件查询审计日志
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> findByMultipleConditions(String userId, AuditAction action, AuditResult result,
                                                  String resourceType, LocalDateTime startTime,
                                                  LocalDateTime endTime, Integer minRiskLevel,
                                                  Pageable pageable) {
        return auditLogRepository.findByMultipleConditions(userId, action, result, resourceType,
                startTime, endTime, minRiskLevel, pageable);
    }
    
    /**
     * 获取用户登录历史
     */
    @Transactional(readOnly = true)
    public Page<AuditLog> getUserLoginHistory(String userId, Pageable pageable) {
        return auditLogRepository.findUserLoginHistory(userId, pageable);
    }
    
    /**
     * 统计用户操作次数
     */
    @Transactional(readOnly = true)
    public Long countUserOperations(String userId, LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.countUserOperations(userId, startTime, endTime);
    }
    
    /**
     * 统计操作类型次数
     */
    @Transactional(readOnly = true)
    public Long countActionOperations(AuditAction action, LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.countActionOperations(action, startTime, endTime);
    }
    
    /**
     * 查找可疑IP地址
     */
    @Transactional(readOnly = true)
    public List<Object[]> findSuspiciousIpAddresses(LocalDateTime startTime, LocalDateTime endTime, Long threshold) {
        return auditLogRepository.findSuspiciousIpAddresses(startTime, endTime, threshold);
    }
    
    /**
     * 获取操作统计
     */
    @Transactional(readOnly = true)
    public List<Object[]> getActionStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.getActionStatistics(startTime, endTime);
    }
    
    /**
     * 获取结果统计
     */
    @Transactional(readOnly = true)
    public List<Object[]> getResultStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.getResultStatistics(startTime, endTime);
    }
    
    /**
     * 清理旧的审计日志
     */
    public void cleanupOldAuditLogs(LocalDateTime cutoffTime) {
        try {
            auditLogRepository.deleteOldAuditLogs(cutoffTime);
            log.info("清理了 {} 之前的审计日志", cutoffTime);
        } catch (Exception e) {
            log.error("清理旧审计日志失败", e);
            throw new RuntimeException("清理旧审计日志失败", e);
        }
    }
}